﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks;
using LiveCharts;
using LiveCharts.Defaults;
using LiveCharts.WinForms;
using LiveCharts.Configurations;
using LiveCharts.Wpf;
using static System.Net.WebRequestMethods;
using System.Windows.Media;
using System.Windows.Forms.VisualStyles;

namespace UDP
{
    public partial class UdpMain : Form
    {

        bool debug = true;
        const int DEBUG_W = 1;//警告
        const int DEBUG_I = 2;//信息
        const int DEBUG_E = 3;//错误
        const int DEBUG_S = 4;//统计
        [DllImport("kernel32.dll")]
        public static extern Boolean AllocConsole();
        [DllImport("kernel32.dll")]
        public static extern Boolean FreeConsole();

        private void DebugWriteLine(string p, int type)
        {
            if (debug)
            {
                Console.BackgroundColor = ConsoleColor.Black;
                switch (type)
                {
                    case DEBUG_E://错误
                        Console.ForegroundColor = ConsoleColor.Red;
                        break;
                    case DEBUG_W://警告
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        break;
                    case DEBUG_S://统计
                        Console.ForegroundColor = ConsoleColor.Blue;
                        break;
                    case DEBUG_I://信息
                        Console.ForegroundColor = ConsoleColor.White;
                        break;
                }
                Console.WriteLine(p);
                Console.ForegroundColor = ConsoleColor.White;
            }
        }

        public const int RECEIVE = 1;
        public const int SEND = 2;
        //安全调用
        delegate void AddMessageToListCallback(string name, byte[] content, int type);
        delegate void timeCallback(object sender, System.Timers.ElapsedEventArgs e);
        //服务器套接字
        private static Socket serverSocket;
        //是否开启了服务
        private bool isServer = false;
        //监听线程
        private Thread receiveTh;

        private bool isSyncSet = false;

        private long countR = 0, countT = 0;

        private System.Timers.Timer timer { get; set; }//定时器，用来作为更新图标动态生成用

        private Random R { get; set; }//为了给Y值提供随机值

        //定时刷新曲线
        private System.Windows.Forms.Timer timerChart;

        private long times = 30;

        private long lastTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
        //采样频率
        private long frequency = 10;
        //采集间隔
        private long intervalTime = 100;//(毫秒)

        public UdpMain()
        {
            //初始化界面
            InitializeComponent();

            InitIntfaceData();

            //定时器
            this.timer = new System.Timers.Timer();
            this.timer.Enabled = true;
            //执行间隔时间,单位为毫秒; 这里实际间隔为1秒钟
            this.timer.Interval = 1000; 
            this.timer.Start();
            this.timer.Elapsed += new System.Timers.ElapsedEventHandler(showTime);
            this.debug = this.checkBox1.Checked;

            if (debug)
            {
                AllocConsole();
                DebugWriteLine("控制台已打开！\n时间：" + DateTime.Now.ToString(
                        "[yyyy-MM-dd HH:mm:ss.fff] "), DEBUG_I);
            }
            R = new Random();

            InitChartValuesData();

            InitChartConfig();

            #region  多Y轴曲线
            //将自定义类型MeasureModel映射到曲线坐标点
            var mapper = LiveCharts.Configurations.Mappers.Xy<DateTimePoint>()
              .X(model => model.Time)    //使用 Time.作为X轴的标签
              .Y(model => model.Value);  //使用Value 作为Y轴的值

            //全局保存映射器
            Charting.For<DateTimePoint>(mapper);
            #endregion

            string _frequency = this.tbFrequency.Text;
            if (_frequency != null && _frequency.Length > 0)
            {
                //转换成长整型
                this.frequency = Convert.ToInt64(_frequency);
                this.intervalTime = 1000 / this.frequency;
            }

                //定时器刷新
                this.timerChart = new System.Windows.Forms.Timer()
                {
                    Interval = (int)(this.intervalTime)
                };
                this.timerChart.Tick += TimerChart_Tick;
                this.timerChart.Start();
            
        }



        private void showTime(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (this.lbSendState.IsDisposed){
                return;
            }

            //处理InvokeRequired，安全调用
            if (this.lbSendState.InvokeRequired){
                timeCallback d = new timeCallback(showTime);
                this.Invoke(d, new object[] { sender, e });
            }else{
                lbSendState.Text = DateTime.Now.ToString("时间  HH:mm:ss");
                lbSendState.Refresh();
            }
        }


        private void InitIntfaceData()
        {
            //得到主机名
            string HostName = Dns.GetHostName();
            if (debug){
                DebugWriteLine("主机名：" + HostName, DEBUG_I);
            }
            //通过主机名获取IP
            IPHostEntry IpEntry = Dns.GetHostEntry(HostName);
            //可变数组
            ArrayList addressList = new ArrayList();

            addressList.Add("0.0.0.0");
            addressList.Add("127.0.0.1");

            for (int i = 0; i < IpEntry.AddressList.Length; i++){
                //从IP地址列表中筛选出IPv4类型的IP地址
                //AddressFamily.InterNetwork表示此IP为IPv4,
                //AddressFamily.InterNetworkV6表示此地址为IPv6类型
                if (IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork){
                    if (debug){
                        DebugWriteLine("IPV4:" + IpEntry.AddressList[i].ToString(), DEBUG_I);
                    }
                    addressList.Add(IpEntry.AddressList[i].ToString());
                }
            }
            //固定大小
            addressList.TrimToSize();
            object[] adList = new object[addressList.Count];
            for (int i = 0; i < addressList.Count; i++){
                adList[i] = addressList[i];
            }
            this.cbMyAddress.Items.AddRange(adList);
            this.cbServerAddress.Items.AddRange(adList);
            this.cbMyAddress.SelectedIndex = 0;
            this.cbServerAddress.SelectedIndex = 0;

        }

        //给消息列表添加消息
        private void AddMessageToList(string name, byte[] content, int type){
            if (this.rtbMessageList.IsDisposed){
                return;
            }
            //处理InvokeRequired，安全调用
            if (this.rtbMessageList.InvokeRequired)
            {
                AddMessageToListCallback d = new AddMessageToListCallback(AddMessageToList);
                this.Invoke(d, new object[] { name, content, type });
            }
            else{
                this.lbSendState.Text = "产生消息";
                this.lbSendState.Refresh();
                string str = "";
                string show = "";
                int i = 0;
                if (this.cbHex.Checked){
                    StringBuilder sb = new StringBuilder();
                    //for (i = 0; i < content.Length && content[i] != 0; i++)
                    //{
                    //    sb.Append(content[i].ToString("X2"));
                    //    sb.Append(" ");
                    //}
                    foreach (byte b in content){
                        //{0:X2} 大写
                        sb.AppendFormat("{0:x2}", b);
                    }
                    show = sb.ToString();
                }else{
                    //for (i = 0; i < content.Length && content[i] != 0; i++) { }
                    //show = Encoding.UTF8.GetString(content, 0, i);
                    show = Encoding.UTF8.GetString(content);
                }

                if (debug){
                    DebugWriteLine("共" + i + "个字符", DEBUG_I);
                }

                //构建消息头
                switch (type){
                    case RECEIVE:
                        this.countR += i;
                        this.rtbMessageList.SelectionColor = System.Drawing.Color.Red;
                        str = DateTime.Now.ToString("[yyyy-MM-dd HH:mm:ss.fff] ") + " 收到：" + name + "\n";
                        break;
                    case SEND:
                        this.countT += i;
                        this.rtbMessageList.SelectionColor = System.Drawing.Color.Orange;
                        str = DateTime.Now.ToString("[yyyy-MM-dd HH:mm:ss.fff] ") + " 发自：" + name + "\n";
                        break;
                }

                //写入消息头
                this.rtbMessageList.AppendText(str);

                //写入消息内容
                this.rtbMessageList.SelectionColor = System.Drawing.Color.Black;

                this.rtbMessageList.AppendText(show);
                this.rtbMessageList.AppendText("\r\n");

                this.lbCount.Text = "接收：" + this.countR + " 发送：" + this.countT;
                this.lbSendState.Text = "";

                if (debug){
                    if (type == SEND){
                        DebugWriteLine("发送消息！发到：" + name + "    内容：" + show, DEBUG_I);
                    }else{
                        DebugWriteLine("收到消息！来自：" + name + "    内容：" + show, DEBUG_I);
                    }
                }
            }
        }

        //点击“开启服务按钮”
        private void btnOpenServer_Click(object sender, EventArgs e){
            //停用按钮，防止多次点击
            this.btnOpenServer.Enabled = false;
            if (debug){
                DebugWriteLine("停用按钮！", DEBUG_I);
            }
            //如果服务是打开的
            if (this.isServer){
                this.lbSendState.Text = "关闭服务器";
                if (debug){
                    DebugWriteLine("服务器处于打开状态！", DEBUG_S);
                }
                //如果套接字不为空
                if (serverSocket != null){
                    //先关闭线程，再关闭服务器
                    this.receiveTh.Abort();
                    if (debug){
                        DebugWriteLine("关闭服务器！", DEBUG_I);
                    }
                    //关闭
                    serverSocket.Close();
                }

                //设置界面为服务关闭状态
                this.lbServerState.Text = "服务器已关闭";
                this.lbServerState.ForeColor = System.Drawing.Color.Blue;
                this.btnOpenServer.Text = "打开服务端口";
                this.pbServerState.BackgroundImage = global::UDP.Properties.Resources.close;
                //允许编辑端口
                this.tbServerPort.ReadOnly = false;
                //允许编辑地址
                this.cbServerAddress.Enabled = true;
                //关闭同步
                this.cbSyncServer.Checked = false;

                //设置服务为关闭状态
                this.isServer = false;
                this.lbSendState.Text = "";
                this.cbMyAddress.Enabled = true;
                this.tbMyPort.Enabled = true;
                this.cbSyncServer.Enabled = true;
                this.tbAbverseIp.Enabled = true;
                this.tbAbversePort.Enabled = true;
                this.cbHex.Enabled = true;
                this.checkBox1.Enabled = true;
            }
            else{
                //如果服务是关闭的
                this.lbSendState.Text = "开启服务器";
                serverSocket = null;
                if (debug){
                    DebugWriteLine("服务器处于关闭状态！", DEBUG_S);
                }
                //获取地址
                string ip = getIPAddress(cbServerAddress.Text);
                if (ip == null){
                    if (debug){
                        DebugWriteLine("服务器地址不正确", DEBUG_E);
                    }
                    MessageBox.Show("服务器地址不正确，请输入IP或者域名！\n域名需要有DNS服务器！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    DebugWriteLine("启用按钮！", DEBUG_I);
                    this.btnOpenServer.Enabled = true;
                    return;
                }
                if (debug){
                    DebugWriteLine("服务器地址：" + ip, DEBUG_S);
                }
                int port = getPort(tbServerPort.Text);
                if (port == -1){
                    if (debug){
                        DebugWriteLine("服务器端口格式不对！", DEBUG_E);
                    }
                    MessageBox.Show("服务器端口格式不对！（值：0 - 65535）", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    if (debug){
                        DebugWriteLine("启用按钮！", DEBUG_I);
                    }
                    this.btnOpenServer.Enabled = true;
                    return;
                }

                if (debug){
                    DebugWriteLine("服务器端口：" + port, DEBUG_S);
                }

                try{
                    if (debug){
                        DebugWriteLine("服务器打开中......", DEBUG_I);
                    }
                    //创建套接字，以UDP的方式
                    serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                    //绑定端口号和IP
                    serverSocket.Bind(new IPEndPoint(IPAddress.Parse(ip), port));
                }catch (SocketException es){
                    //出现异常
                    if (debug){
                        DebugWriteLine("出现异常：" + es.ErrorCode + "！", DEBUG_E);
                    }
                    MessageBox.Show("绑定端口时出现异常：" + es.ErrorCode + "！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }finally{
                    if (debug){
                        DebugWriteLine("启用按钮！", DEBUG_S);
                    }
                    //按钮启用
                    btnOpenServer.Enabled = true;
                }
                //如果打开了并且绑定端口了
                if (serverSocket != null && serverSocket.IsBound){
                    if (debug){
                        DebugWriteLine("服务器开启成功！", DEBUG_I);
                    }

                    //UI显示
                    //设置界面为服务打开状态
                    this.lbServerState.Text = "服务器已开启";
                    this.lbServerState.ForeColor = System.Drawing.Color.Red;
                    this.btnOpenServer.Text = "关闭服务";
                    this.pbServerState.BackgroundImage = global::UDP.Properties.Resources.open;
                    //不允许编辑端口
                    this.tbServerPort.ReadOnly = true;
                    //不允许编辑地址
                    this.cbServerAddress.Enabled = false;
                    //设置服务为打开状态
                    this.isServer = true;

                    this.cbMyAddress.Enabled = false;
                    this.tbMyPort.Enabled = false;
                    this.cbSyncServer.Enabled = false;
                    this.tbAbverseIp.Enabled = false;
                    this.tbAbversePort.Enabled = false;
                    this.cbHex.Enabled = false;
                    this.checkBox1.Enabled = false;
                    //开启接收消息线程
                    this.receiveTh = new Thread(ReciveMsg);
                    this.receiveTh.Start();

                    //打开同步
                    this.cbSyncServer.Checked = true;
                }
            }

            if (debug){
                DebugWriteLine("启用按钮！", DEBUG_S);
            }
            this.btnOpenServer.Enabled = true;
            this.lbSendState.Text = "";
        }

        //发送数据报
        private void btnSendMessage_Click(object sender, EventArgs e)
        {
            if (!isServer){
                MessageBox.Show("请先打开服务端口！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            this.lbSendState.Text = "发送数据报";
            //表示这个是不是服务器的套接字
            bool isUseServer = false;
            Socket clientSocket = null;
            //停用按钮，防止多次点击
            this.btnSendMessage.Enabled = false;
            if (debug){
                DebugWriteLine("停用按钮！", DEBUG_S);
            }
            //如果服务是打开的
            if (this.isServer
                    && (serverSocket != null)
                    && this.cbServerAddress.Text.Equals(this.cbMyAddress.Text)
                    && this.tbServerPort.Text.Equals(tbMyPort.Text))
            { //并且服务器和发送的设置是一样的
                isUseServer = true;
                //直接使用服务器的套接字
                clientSocket = serverSocket;
            }else{//如果服务是关闭的,或者设置不同
                string myIp = getIPAddress(this.cbMyAddress.Text);//获取地址
                if (myIp == null){
                    if (debug){
                        DebugWriteLine("发送端地址不正确", DEBUG_E);
                    }
                    MessageBox.Show("发送端地址不正确，请输入IP或者域名！\n域名需要有DNS服务器！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    DebugWriteLine("启用按钮！", DEBUG_I);
                    this.btnSendMessage.Enabled = true;
                    return;
                }
                if (debug){
                    DebugWriteLine("发送端地址：" + myIp, DEBUG_S);
                }
                int myPort = getPort(this.tbMyPort.Text);
                if (myPort == -1){
                    if (debug){
                        DebugWriteLine("发送端端口格式不对！", DEBUG_E);
                    }
                    MessageBox.Show("发送端端口格式不对！（值：0 - 65535）", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    if (debug){
                        DebugWriteLine("启用按钮！", DEBUG_I);
                    }
                    this.btnSendMessage.Enabled = true;
                    return;
                }

                if (debug){
                    DebugWriteLine("发送端端口：" + myPort, DEBUG_S);
                }
                //创建套接字
                clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                //绑定端口号和IP
                clientSocket.Bind(new IPEndPoint(IPAddress.Parse(myIp), myPort));
            }
            //获取地址
            string adIp = getIPAddress(this.tbAbverseIp.Text);
            if (adIp == null){
                if (debug){
                    DebugWriteLine("对方主机地址不正确", DEBUG_E);
                }
                MessageBox.Show("对方主机地址不正确，请输入IP或者域名！\n域名需要有DNS服务器！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                if (debug){
                    DebugWriteLine("启用按钮！", DEBUG_I);
                }
                this.btnSendMessage.Enabled = true;
                return;
            }
            if (debug){
                DebugWriteLine("对方主机地址：" + adIp, DEBUG_S);
            }
            //对方端口
            int adPort = getPort(this.tbAbversePort.Text);
            if (adPort == -1){
                if (debug){
                    DebugWriteLine("对方主机端口格式不对！", DEBUG_E);
                }
                MessageBox.Show("对方主机端口格式不对！（值：0 - 65535）", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                if (debug){
                    DebugWriteLine("启用按钮！", DEBUG_I);
                }
                this.btnSendMessage.Enabled = true;
                return;
            }

            if (debug){
                DebugWriteLine("接收端端口：" + adPort, DEBUG_S);
            }
            //设置好地址
            EndPoint adversePoint = new IPEndPoint(IPAddress.Parse(adIp), adPort);
            try{
                string msg = this.btnSendMessage.Text;
                if ((!string.IsNullOrEmpty(msg)) && ("启动".Equals(msg))){
                    string _frequency = this.tbFrequency.Text;
                    if (_frequency != null && _frequency.Length > 0)
                    {
                        //转换成长整型
                        this.frequency = Convert.ToInt64(_frequency);
                        this.intervalTime = 1000 / this.frequency;
                    }
                    //如果不为空
                    //byte[] bmsg = Encoding.UTF8.GetBytes(msg);
                    byte[] bmsg = { 0x30, 0x02, 0x06, 0x00, 0x00, 0x00 };
                    if (bmsg != null){
                        if (this.cbAddRN.Checked){
                            byte[] rn = new byte[2];
                            rn[0] = 0x0d;//13,\r
                            rn[1] = 0x0a;//10,\n

                            bmsg = bmsg.Concat(rn).ToArray();
                        }
                    }
                    //发送数据包
                    clientSocket.SendTo(bmsg, adversePoint);
                    //UI显示
                    AddMessageToList(adversePoint.ToString(), bmsg, SEND);
                    this.btnSendMessage.Text = "停止";
                    this.tbFrequency.Enabled = false;
                    this.btnClearInput.Enabled = false;
                }
                else{
                    byte[] bmsg = { 0x30, 0x01, 0x06, 0x00, 0x00, 0x00 };
                    if (bmsg != null)
                    {
                        if (this.cbAddRN.Checked)
                        {
                            byte[] rn = new byte[2];
                            rn[0] = 0x0d;//13,\r
                            rn[1] = 0x0a;//10,\n

                            bmsg = bmsg.Concat(rn).ToArray();
                        }
                    }
                    //发送数据包
                    clientSocket.SendTo(bmsg, adversePoint);
                    //UI显示
                    AddMessageToList(adversePoint.ToString(), bmsg, SEND);
                    this.btnSendMessage.Text = "启动";
                    this.tbFrequency.Enabled = true;
                    this.btnClearInput.Enabled = true;
                    //if (debug){
                    //    DebugWriteLine("发送数据格式错误：" + msg, DEBUG_E);
                    //}
                    //MessageBox.Show("发送数据格式错误：" + msg, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            catch (SocketException es){
                if (debug){
                    DebugWriteLine("出现异常：" + es.ErrorCode + "！", DEBUG_E);
                }
                MessageBox.Show("发送数据报时出现异常：" + es.ErrorCode + "！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            //如果是新开的套接字
            if (!isUseServer){
                if (clientSocket != null){
                    //用完之后关掉
                    clientSocket.Close();
                }
            }

            if (debug){
                DebugWriteLine("启用按钮！", DEBUG_S);
            }
            this.btnSendMessage.Enabled = true;
            this.lbSendState.Text = "";
        }

        // 接收发送给本机IP对应端口号的数据报
        private void ReciveMsg(){
            try{
                while (this.isServer){
                    //用来保存发送方的IP和端口号
                    EndPoint point = new IPEndPoint(IPAddress.Any, 0);
                    //消息缓存区申请
                    byte[] buffer = new byte[512];
                    //接收数据报
                    int length = serverSocket.ReceiveFrom(buffer, ref point);
                    if (debug){
                        DebugWriteLine("接收数据长度 length：" + length, DEBUG_I);
                    }
                    byte[] revBuf = new byte[length];
                    Buffer.BlockCopy(buffer, 0, revBuf, 0, length);
                    //显示在消息列表里
                    //AddMessageToList(point.ToString(), revBuf, RECEIVE);
                    //显示在波形图里
                    this.refreshData(revBuf);
                }
            }
            catch (SocketException e){
                DebugWriteLine(e.Message, DEBUG_E);
            }
        }


        //窗口关闭事件委托，在窗口关闭事件前处理
        private void UdpForm_FormClosing(object sender, FormClosingEventArgs e){
            this.isServer = false;
            if (this.receiveTh != null){
                if (debug){
                    DebugWriteLine("关闭接收线程！", DEBUG_I);
                }
                this.receiveTh.Abort();
            }
            if (serverSocket != null){
                if (debug){
                    DebugWriteLine("关闭服务器！", DEBUG_I);
                }
                serverSocket.Close();
            }
            if (debug){
                DebugWriteLine("关闭窗口！", DEBUG_I);
            }
        }

        //清空消息列表
        private void btnClearList_Click(object sender, EventArgs e){
            if (debug){
                DebugWriteLine("清空消息列表！", DEBUG_I);
            }
            this.rtbMessageList.Text = "";
        }

        //清空输入框
        private void btnClearInput_Click(object sender, EventArgs e){
            if (debug){
                DebugWriteLine("清空输入框！", DEBUG_I);
            }
            this.tbFrequency.Text = "1";
        }

        //根据字符串获取端口
        private int getPort(string str){
            if (!IsPort(str)){
                //不是端口
                return -1;
            }
            //转换成整型
            int port = Convert.ToInt32(str);
            if (port >= 0 && port <= 65535){
                //如果是合法端口
                return port;
            }
            else{//不是合法端口
                return -1;
            }
        }

        //根据字符串获取IP地址
        string getIPAddress(string str){
            if (!IsIP(str)){
                //如果不是IP
                if (IsDomain(str)){
                    //如果是域名
                    try
                    {
                        //解析域名
                        IPAddress[] host = Dns.GetHostAddresses(str);
                        //域名解析的IP地址
                        IPAddress ipAddress = host[0];
                        //改成IP地址
                        str = ipAddress.ToString();
                    }catch{
                        return null;
                    }
                }else{
                    return null;
                }
            }
            //返回IP地址
            return str;
        }

        // 验证字符串是否是域名
        public bool IsDomain(string str){
            string pattern = @"^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$";
            return IsMatch(pattern, str);
        }

        // 验证字符串是否是IP
        bool IsIP(string str){
            string pattern = @"(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)";
            return IsMatch(pattern, str);
        }

        //判断是否为0-65535的数字
        bool IsPort(string str){
            string pattern = @"^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$";
            return IsMatch(pattern, str);
        }

        // 判断一个字符串，是否匹配指定的表达式(区分大小写的情况下)
        public bool IsMatch(string expression, string str){
            Regex reg = new Regex(expression);
            if (string.IsNullOrEmpty(str)){
                return false;
            }
            return reg.IsMatch(str);
        }

        //勾选与取消勾选“与服务器同步设置”
        private void cbSyncServer_CheckedChanged(object sender, EventArgs e){
            CheckBox cb = (CheckBox)sender;
            if (cb.Equals(this.cbSyncServer)){
                if (cb.Checked){
                    //同步设置
                    this.isSyncSet = true;
                    this.cbMyAddress.Enabled = false;
                    this.tbMyPort.ReadOnly = true;
                    //复制服务器的地址
                    this.cbMyAddress.Text = cbServerAddress.Text;
                    //复制服务器的端口
                    this.tbMyPort.Text = tbServerPort.Text;
                }else{
                    //不同步设置
                    this.isSyncSet = false;
                    this.cbMyAddress.Enabled = true;
                    this.tbMyPort.ReadOnly = false;
                }
            }
        }

        //同步地址事件
        private void cbServerAddress_TextChanged(object sender, EventArgs e){
            if (this.isSyncSet){
                //复制服务器的地址
                this.cbMyAddress.Text = cbServerAddress.Text;
            }
        }

        //同步端口事件
        private void tbServerPort_TextChanged(object sender, EventArgs e){
            if (this.isSyncSet){
                //复制服务器的端口
                this.tbMyPort.Text = tbServerPort.Text;
            }
        }

        /// <summary>
        /// 实现自动下拉
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void rtbMessageList_TextChanged(object sender, EventArgs e){
            this.rtbMessageList.SelectionStart = rtbMessageList.Text.Length;
            this.rtbMessageList.ScrollToCaret();
        }

        private void lbHelp_Click(object sender, EventArgs e){
            MessageBox.Show("这个程序是一个UDP收发器，能接收和发送UDP报文。\nUDP广播地址：***.***.***.255\n2020-4 Minuy.top 网络编程作业\n开源地址：https://gitee.com/minuy/udp-transceiver", "帮助", MessageBoxButtons.OK);
        }

        private void CartesianChart1OnDataClick(object sender, ChartPoint chartPoint){
            MessageBox.Show("You clicked (" + chartPoint.X + "," + chartPoint.Y + ")");
        }

        private ChartValues<DateTimePoint> InitChartValuesData(){
            ChartValues<DateTimePoint> chartValues = new ChartValues<DateTimePoint>();
            for (long i = 1; i <= 30; i++){
                chartValues.Add(new DateTimePoint(i, R.NextDouble()));
            }
            return chartValues;
        }

        private void InitChartConfig(){
            //添加三条曲线
            OscChart.Series.Add(new LineSeries{
                Title = "通道1",
                PointGeometry = DefaultGeometries.Circle,
                PointGeometrySize = 15,
                StrokeThickness = 4,
                LineSmoothness = 0,
                PointForeground = System.Windows.Media.Brushes.Blue,
                Values = InitChartValuesData(),
                ScalesYAt = 0
            });

            OscChart.Series.Add(new LineSeries{
                Title = "通道2",
                PointGeometry = DefaultGeometries.Circle,
                PointGeometrySize = 15,
                StrokeThickness = 4,
                LineSmoothness = 0,
                PointForeground = System.Windows.Media.Brushes.Green,
                Values = InitChartValuesData(),
                ScalesYAt = 1
            });

            OscChart.Series.Add(new LineSeries{
                Title = "通道3",
                PointGeometry = DefaultGeometries.Circle,
                PointGeometrySize = 15,
                StrokeThickness = 4,
                LineSmoothness = 0,
                PointForeground = System.Windows.Media.Brushes.Red,
                Values = InitChartValuesData(),
                ScalesYAt = 2
            });

            OscChart.Series.Add(new LineSeries{
                Title = "通道4",
                PointGeometry = DefaultGeometries.Circle,
                PointGeometrySize = 15,
                StrokeThickness = 4,
                LineSmoothness = 0,
                PointForeground = System.Windows.Media.Brushes.Yellow,
                Values = InitChartValuesData(),
                ScalesYAt = 3
            });

            OscChart.AxisX.Add(new Axis{
                Title = "时间",
                FontSize = 12,
                DisableAnimations = true,
                Foreground = System.Windows.Media.Brushes.Black,
                //LabelFormatter = value => value.ToString(),
                LabelFormatter = value => new System.DateTime(System.DateTime.Now.Ticks - (long)(this.times - (long)value) * this.intervalTime * 10000).ToString("HH:mm:ss"),
                Separator = new Separator{
                    Step = 1,
                    IsEnabled = true
                },
                MaxValue = this.times,
                MinValue = this.times - 30
            });

            //添加3条Y坐标轴
            OscChart.AxisY.Add(new Axis{
                Title = "波长1",
                FontSize = 12,
                Foreground = System.Windows.Media.Brushes.DodgerBlue,
                Position = AxisPosition.LeftBottom
            });

            OscChart.AxisY.Add(new Axis{
                Title = "波长2",
                FontSize = 12,
                Foreground = System.Windows.Media.Brushes.IndianRed,
                Position = AxisPosition.LeftBottom
            });

            OscChart.AxisY.Add(new Axis{
                Title = "波长3",
                FontSize = 12,
                Foreground = System.Windows.Media.Brushes.DarkOliveGreen,
                Position = AxisPosition.RightTop
            });

            OscChart.AxisY.Add(new Axis{
                Title = "波长4",
                FontSize = 12,
                Foreground = System.Windows.Media.Brushes.YellowGreen,
                Position = AxisPosition.RightTop
            });
        }

        private void TimerChart_Tick(object sender, EventArgs e){
            if ((debug) && (!this.isServer)){
                LineSeriesRefresh();
            }
        }

        /// <summary>
        /// 连续折现图的方法
        /// </summary>
        private void LineSeriesRefresh(){
            this.times++;

            if (this.cbChannel1.Checked) {
                //更新纵坐标数据
                double _trend = R.NextDouble() * 10;
                OscChart.Series[0].Values.Add(new DateTimePoint(this.times, _trend));
                int _count = OscChart.Series[0].Values.Count;
                if (_count > 30){
                    //只关心前面30个数据
                    OscChart.Series[0].Values.RemoveAt(0);
                }
            }
            if (this.cbChannel2.Checked) {
                double _trend = R.NextDouble() * 100;
                OscChart.Series[1].Values.Add(new DateTimePoint(this.times, _trend));
                int _count = OscChart.Series[1].Values.Count;
                if (_count > 30){
                    //只关心前面30个数据
                    OscChart.Series[1].Values.RemoveAt(0);
                }
            }
            if (this.cbChannel3.Checked) {
                double _trend = R.NextDouble() * 1000;
                OscChart.Series[2].Values.Add(new DateTimePoint(this.times, _trend));
                int _count = OscChart.Series[2].Values.Count;
                if (_count > 30){
                    //只关心前面30个数据
                    OscChart.Series[2].Values.RemoveAt(0);
                }
            }
            if (this.cbChannel4.Checked){
                double _trend = R.NextDouble() * 10000;
                OscChart.Series[3].Values.Add(new DateTimePoint(this.times, _trend));
                int _count = OscChart.Series[3].Values.Count;
                if (_count > 30){
                    //只关心前面30个数据
                    OscChart.Series[3].Values.RemoveAt(0);
                    
                }
            }
            // 假设你在非UI线程上
            if (OscChart.InvokeRequired){
                OscChart.Invoke(new Action(() =>{
                    //在这里进行UI相关的操作，例如修改OscChart的属性等
                    OscChart.AxisX[0].MaxValue = this.times;
                    OscChart.AxisX[0].MinValue = this.times - 30;
                    OscChart.Refresh();
                }));
            }else{
                // 直接进行操作，因为当前线程就是UI线程
                OscChart.AxisX[0].MaxValue = this.times;
                OscChart.AxisX[0].MinValue = this.times - 30;
                OscChart.Refresh();
            }
            OscChart.Refresh();
        }

        private void refreshData(byte[] revData){

            if (revData.Length != 494){
                return;
            }

            long nowTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
            if ((nowTime - this.lastTime) < this.intervalTime){
                return;
            }
            this.lastTime = nowTime;
            this.times++;
            byte cmd = revData[0];
            byte code = revData[1];
            byte[] tempArray = new byte[4];
            Array.Copy(revData, 2, tempArray, 0, 4);
            uint length = BitConverter.ToUInt32(tempArray, 0);
            for (int channalIndex = 0; channalIndex < 4; channalIndex++){
                byte[] tempChannelArray = new byte[122];
                Array.Copy(revData, 122 * channalIndex + 6, tempChannelArray, 0, 122);
                byte[] tempNodeArray = new byte[4];
                Array.Copy(tempChannelArray, 0, tempNodeArray, 0, 4);
                double _trend = 0.00001d;
                uint yValue = (UInt32)((tempNodeArray[0] << 24) | (tempNodeArray[1] << 16) | (tempNodeArray[2] << 8) | tempNodeArray[3]);
                if (yValue > 0){
                    _trend = (double)DivideAndRound(2997924608L, yValue, 5);
                    //添加y值，_trend为数据
                    var pointValue = new DateTimePoint(this.times, _trend);
                    //OscChart.Series[channalIndex].Values.Add(pointValue);
                    ////lets only use the last 30 values
                    //if (OscChart.Series[channalIndex].Values.Count > 30)
                    //{
                    //    OscChart.Series[channalIndex].Values.RemoveAt(0);
                    //}
                    if ((this.cbChannel1.Checked)&&(channalIndex == 0)){
                        //更新纵坐标数据
                        OscChart.Series[0].Values.Add(pointValue);
                        int _count = OscChart.Series[0].Values.Count;
                        if (_count > 30)
                        {
                            //只关心前面30个数据
                            OscChart.Series[0].Values.RemoveAt(0);
                        }
                    }
                    else if ((this.cbChannel2.Checked)&&(channalIndex == 1)){
                        OscChart.Series[1].Values.Add(pointValue);
                        int _count = OscChart.Series[1].Values.Count;
                        if (_count > 30)
                        {
                            //只关心前面30个数据
                            OscChart.Series[1].Values.RemoveAt(0);
                        }
                    }
                    else if((this.cbChannel3.Checked)&&(channalIndex == 2)){
                        OscChart.Series[2].Values.Add(pointValue);
                        int _count = OscChart.Series[2].Values.Count;
                        if (_count > 30){
                            //只关心前面30个数据
                            OscChart.Series[2].Values.RemoveAt(0);
                        }
                    }
                    else if((this.cbChannel4.Checked)&&(channalIndex == 3)){
                        OscChart.Series[3].Values.Add(pointValue);
                        int _count = OscChart.Series[3].Values.Count;
                        if (_count > 30){
                            //只关心前面30个数据
                            OscChart.Series[3].Values.RemoveAt(0);
                        }
                    }
                }
            }

            // 假设你在非UI线程上
            if (OscChart.InvokeRequired){
                OscChart.Invoke(new Action(() =>{
                    // 在这里进行UI相关的操作，例如修改OscChart的属性等
                    OscChart.AxisX[0].MaxValue = this.times;
                    OscChart.AxisX[0].MinValue = this.times - 30;
                    OscChart.Refresh();
                }));
            }else{
                // 直接进行操作，因为当前线程就是UI线程
                OscChart.AxisX[0].MaxValue = this.times;
                OscChart.AxisX[0].MinValue = this.times - 30;
                OscChart.Refresh();
            }
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            this.debug = this.checkBox1.Checked;
        }

        public static decimal DivideAndRound(decimal dividend, decimal divisor, int decimalPlaces){
            if (divisor == 0){
                throw new DivideByZeroException();
            }
            decimal result = dividend / divisor;
            return Math.Round(result, decimalPlaces);
        }

    }
}

